package de.hohenheim.view.mobile.animation;

import java.util.ArrayList;
import java.util.Random;

import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.ManhattanConnectionRouter;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.draw2d.geometry.Rectangle;
import de.hohenheim.view.map.RoomMap;
import de.hohenheim.view.path.PathFigure;
import de.hohenheim.view.room.RoomFigure;

/**
 * Utility class for animation. 
 * @author Marc Fernandes
 *
 */
public class Utils {

	/**
	 * Randomly calculates a {@link Point} in a room.
	 * @param roomanchor - The Room we want to calculate the point. 
	 * @param int x_offset - We take the center of the animationFigure as Point, so we need the offset.
	 * @param int y_offset - We take the center of the animationFigure as Point, so we need the offset.
	 * @return
	 */
	private static Point randomPointInRoom(ConnectionAnchor roomanchor, int x_offset, int y_offset) {
		Rectangle r          = roomanchor.getOwner().getBounds();
		Random randGenerator = new Random();
		int x                = r.x+x_offset+randGenerator.nextInt(r.width-(2*x_offset+1));
		int y                = r.y+y_offset+randGenerator.nextInt(r.height-(2*y_offset+1));
		return new Point(x,y);
	}
	
	/**
	 * Randomly selects a path which begins at the specified room.
	 * @param {@link RoomMap} map - The RoomMap where the room is located. 
	 * @param {@link RoomFigure} start_room - The room is the starting point. 
	 * 		  We must look randomly for a path which lead away from this room.
	 * @return {@link PathFigure} - The path we selected randomly.
	 */
	public static PathFigure getRandomPath(RoomMap map, RoomFigure start_room) {
		  ArrayList<PathFigure> edges = map.getPaths().get(start_room);	  
		  Random generator = new Random();
		  int index =  generator.nextInt(edges.size());	  
		  return (PathFigure)edges.get(index);
	}
	
	/**
	 * 1. Extracts segments out of one path. We use a {@link ManhattanConnectionRouter} to route the path
	 * so the polyline which is drawn as path can have orthogonal lines (with start and end point).This is why all these lines must be  
	 * separated into segments.
	 * 
	 * 2. If we have extracted the points, we calculate all points between all segments and add them as PointLists.
	 * We need this because we then can animate through every single point.
	 * 
	 * @param {@link PathFigure} path - The path from which we want to have the segments and PointLists of each segment.
	 * @param {@link RoomFigure} end_room - The RoomFigure to which the path leads. We need this because we need a direction.
	 * @param {@link Figure} mobile - the Figure we animate. 
	 * @return
	 */
	public static PointList[] getSegments(PathFigure path, RoomFigure end_room, Figure mobile) {		
		PointList pathPoints = new PointList();
		Point start_ref = null;
		int x_offset = mobile.getBounds().width/2;
		int y_offset = mobile.getBounds().height/2;
		
		start_ref = mobile.getLocation().translate(x_offset, y_offset);
		pathPoints.addPoint(start_ref);
		
		if(path == null) 
			return new PointList[0];
		if(path.getSourceAnchor().getOwner()!=end_room) {
		  pathPoints.addAll(path.getPoints());
		} else {
			PointList tmp = path.getPoints();
			for(int i=tmp.size()-1;  i>=0; i--) {
			  pathPoints.addPoint(tmp.getPoint(i));
			}
		}
		
		Point end_ref; 
		if(path.getSourceAnchor().getOwner()==end_room) {
		  end_ref = Utils.randomPointInRoom(path.getSourceAnchor(), x_offset, y_offset);//path.getTargetAnchor().getReferencePoint();
		} else {
			end_ref = Utils.randomPointInRoom(path.getTargetAnchor(), x_offset, y_offset);//path.getSourceAnchor().getReferencePoint();
		}
		pathPoints.addPoint(end_ref);
		
		int nr_segments = pathPoints.size()-1;
		PointList[] retVal = new PointList[nr_segments];
		
		
		for(int i=0; i<nr_segments;i+=1) {
		  PointList plist = new PointList();
		  Point start = pathPoints.getPoint(i);
		  Point end   = pathPoints.getPoint(i+1);
		  int dx = end.x-start.x;
		  int dy = end.y-start.y;
		  int sig_dx = new Float(Math.signum(dx)).intValue(); //negativ, positiv oder 0? --> Vorzeichen
		  int sig_dy = new Float(Math.signum(dy)).intValue();
		  
		  int max = Math.max(Math.abs(dx),Math.abs(dy));
		  int step_y=0;
		  int step_x=0;
		  for(int j=0; j<max; j++) {
			if(step_y!=dy) {
				step_y=step_y+sig_dy;
			}
			if(step_x!=dx) {
				step_x=step_x+sig_dx;
			}
			plist.addPoint(new Point(start.x-x_offset+step_x, start.y+step_y-y_offset));
		  }		  
		  retVal[i]=plist;
		}
		
		//Only from the location point of that path we need the segments, because we are already on the path.
		//if we do not find anything, we must not cut anything!
		int i_index=0;
		int j_index=0;
		for (int i=0; i<retVal.length; i++) {
			for(int j=0; j<retVal[i].size(); j++) {
			  if(retVal[i].getPoint(j).equals(mobile.getLocation())) {					
				i_index=i;
				j_index=j;
				break;
			  }						
			}
			
		}
		//New Length. We cut away all Segments(Pointlists) we did already completely walk.
		PointList[] tmp = new PointList[retVal.length-i_index];
		System.arraycopy(retVal, i_index, tmp, 0, retVal.length-i_index);
		//Now we cut off the points we already walked on the last segment!
		for(int i=0; i< j_index; i++) {
			tmp[0].removePoint(0);
		}
		
		return tmp;
	}	
	
}
